package com.panopset.sf;

import java.awt.Dimension;
import java.awt.FileDialog;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import javax.swing.JComponent;
import javax.swing.JFrame;

import com.google.inject.Inject;
import com.panopset.RezIO;
import com.panopset.Strings;
import com.panopset.Util;
import com.panopset.centralen.UniqueKey;
import com.panopset.centralen.util.MathUtil;

/**
 * Window document glue.
 *
 * @author Karl Dinwiddie
 *
 */
public final class Windoc {

    /**
     * Owner Application.
     */
    @Inject
    private App app;

    private JFrame f;

    private static final List<String> titles = new ArrayList<String>();

    /**
     * Title.
     */
    private String title;

    /**
     *
     * @param e
     *            KeyEvent.
     */
    public void dispatchKeyEvent(final KeyEvent e) {
        if (kl.isEmpty()) {
            return;
        }
        for (KeyListener l : kl) {
            if (e.getID() == KeyEvent.KEY_PRESSED) {
                l.keyPressed(e);
            } else if (e.getID() == KeyEvent.KEY_RELEASED) {
                l.keyReleased(e);
            } else if (e.getID() == KeyEvent.KEY_TYPED) {
                l.keyTyped(e);
            }
        }
    }

    private List<KeyListener> kl = new ArrayList<KeyListener>();

    public void addKeyListener(KeyListener keyListener) {
        kl.add(keyListener);
    }

    /**
     *
     * @return Title. Default is &quot;Untitled.&lt;name&gt;.txt&quot;.
     */
    public String getTitle() {
        if (title == null) {
            if (file == null) {
                int i = 0;
                final StringWriter pfx = new StringWriter();
                pfx.append("Untitled");
                final StringWriter sfx = new StringWriter();
                sfx.append(".");
                sfx.append(app.getApplicationName().toLowerCase());
                sfx.append(".txt");
                StringWriter sw = new StringWriter();
                sw.append(pfx.toString());
                sw.append(sfx.toString());
                while (titles.contains(sw.toString())) {
                    sw = new StringWriter();
                    sw.append(pfx.toString());
                    sw.append("" + i++);
                    sw.append(sfx.toString());
                }
                title = sw.toString();
                titles.add(title);
            } else {
                title = RezIO.getCanonicalPath(file);
            }
        }
        return title;
    }

    /**
     *
     * @return Application.
     */
    public App getApp() {
        return app;
    }

    int x, y, w, h;
    public JFrame getFrame() {
        if (f == null) {
            JComponent c = app.createWindowComp(this);
            if (c == null) {
                return null;
            }
            f = new JFrame();
            getProperties();

            w = MathUtil.getIntValue(p
                    .getProperty(App.APP_PROPS_KEY_LAST_WIDTH));

            h = MathUtil.getIntValue(p
                    .getProperty(App.APP_PROPS_KEY_LAST_HEIGHT));
            if (!(w > 0 && h > 0)) {
                w = app.getDefaultSize().width;
                h = app.getDefaultSize().height;
            }
            x = MathUtil.getIntValue(p
                    .getProperty(App.APP_PROPS_KEY_LAST_XLOC));
            y = MathUtil.getIntValue(p
                    .getProperty(App.APP_PROPS_KEY_LAST_YLOC));
            if (!(x > 0 && y > 0)) {
                Point cp = Util.centerInScreen(new Dimension(w, h));
                x = cp.x;
                y = cp.y;
            }
            f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            f.setIconImage(app.getFavicon().getImageResource().getImage());
            f.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosed(final WindowEvent e) {
                    doClose();
                }
            });
            f.setLayout(new GridLayout(1, 1));
            f.add(c);
            f.setJMenuBar(new AppMenuBar(this).getMenuBar());
            f.setTitle(getTitle() + " - " + app.getApplicationName());
            for (Entry<String, Grounding> e : pfs.entrySet()) {

                p.put(e.getKey(), e.getValue().getValue());

            }
        }
        return f;
    }

    private Properties p;

    private Properties getProperties() {
        if (p == null) {
            p = new Properties();
            if (getFile().exists()) {
                try {
                    p.load(new FileReader(getFile()));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return p;
    }

    /**
     * File.
     */
    private File file;

    /**
     * @return File.
     */
    public File getFile() {
        if (file == null) {
            file = new File(System.getProperty("user.home") + Strings.FILE_SEP
                    + app.getUserBaseDirectory()

                    + Strings.FILE_SEP + getTitle());
        }
        return file;
    }

    /**
     * Register a persistent field.
     *
     * @param g
     *            Grounding.
     * @param dft
     *            Default.
     * @param key
     *            Persistent store key. If the key is empty, a key will be
     *            generated based on the stack trace. If the key is null, there
     *            will be no registration.
     */
    public final void registerGrounding(final Grounding g, final String dft,
            final String key) {
        if (key == null) {
            return;
        }
        String k = key;
        if ("".equals(key)) {
            k = UniqueKey.generateStackHashKey();
        }
        if (!pfs.containsKey(k)) {
            pfs.put(k, g);
        }
        String val = getProperties().getProperty(k);
        if (Strings.isPopulated(val)) {
            g.setValue(val);
        } else {
            g.setValue(dft);
        }
    }

    /**
     * Persistent fields.
     */
    private Map<String, Grounding> pfs

    = new HashMap<String, Grounding>();

    public void doClose() {
        if (app.getXref().containsKey(f)) {
            doSave();
            app.saveAttrs(f);
            app.getXref().remove(f);
            f.setVisible(false);
            f.dispose();
            if (app.getXref().isEmpty()) {
                app.shutdown();
            }
        }
    }

    public void doOpen() {
        app.doOpen(UserFile.getFileFromUser(getFile(), Util.x("Open"),
                FileDialog.LOAD));
    }

    public void doNew() {
        app.doNew();
    }

    public void setFile(final File newFile) {
        file = newFile;
    }

    public void doSaveAs() {
        setFile(UserFile.getFileFromUser(getFile(), Util.x("Save as"),
                FileDialog.SAVE));
        doSave();
    }

    /**
     * Save windoc data.
     */
    public void doSave() {
        p = new Properties();
        p.put(App.APP_PROPS_KEY_LAST_WIDTH, ""
                + new Double(f.getSize().getWidth()).intValue());
        p.put(App.APP_PROPS_KEY_LAST_HEIGHT, ""
                + new Double(f.getSize().getHeight()).intValue());
        p.put(App.APP_PROPS_KEY_LAST_XLOC, ""
                + new Double(f.getLocation().getX()).intValue());
        p.put(App.APP_PROPS_KEY_LAST_YLOC, ""
                + new Double(f.getLocation().getY()).intValue());
        for (Entry<String, Grounding> e : pfs.entrySet()) {
            App.msg = "Saving " + e.getKey() + ".";
            p.put(e.getKey(), e.getValue().getValue());
        }
        try {
            if (!getFile().getParentFile().exists()) {
                getFile().getParentFile().mkdirs();
            }
            p.store(new FileWriter(getFile()), app.getApplicationName());
            title = null;
            getFrame().setTitle(getTitle());
        } catch (IOException e) {
            Util.log(e);
        }
    }

    /**
     * Show the frame.
     */
    public void show() {
        getFrame().setVisible(true);
        getFrame().setSize(w, h);
        getFrame().setLocation(x, y);
    }

}
